package nl.vu.few.ibivu.biomodels.client.presenter;

import com.google.gwt.event.shared.EventBus;
import com.google.gwt.place.shared.PlaceController;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Widget;
import com.google.inject.Inject;

import nl.vu.few.ibivu.biomodels.client.BioModels;
import nl.vu.few.ibivu.biomodels.client.GatewayServiceAsync;
import nl.vu.few.ibivu.biomodels.client.event.LoginStateChangedEvent;
import nl.vu.few.ibivu.biomodels.client.event.MessageBroadcastType;
import nl.vu.few.ibivu.biomodels.client.event.RequestLoginStateCheckEvent;
import nl.vu.few.ibivu.biomodels.client.event.RequestLoginStateCheckEventHandler;
import nl.vu.few.ibivu.biomodels.client.ui.view.GatewayView;
import nl.vu.few.ibivu.biomodels.client.ui.view.GatewayView.Presenter;
import nl.vu.few.ibivu.biomodels.shared.AuthenticationProvider;
import nl.vu.few.ibivu.biomodels.shared.UserInfo;

public class GatewayPresenter extends AbstractPresenter implements Presenter, RequestLoginStateCheckEventHandler {
	
	private GatewayServiceAsync gws;
	private UserInfo userInfo;
	private GatewayView view;
	
	@Inject
	public GatewayPresenter(PlaceController placeController, EventBus eventBus, GatewayServiceAsync gws, GatewayView view) {
		super(eventBus, placeController);
		this.eventBus = eventBus;
		this.view = view;
		this.gws = gws;
		exposeCheckLogin(this);
		RequestLoginStateCheckEvent.register(eventBus, this);
		userInfo = BioModels.getUserInfo();
		this.view.setPresenter(this);
		this.view.setUserInfo(userInfo);
	}

	private boolean stateChanged(UserInfo current, UserInfo result) {
		if (result.isLoggedIn()) {
			// if the component has not been initialized yet and the user just logged in
			if (current == null) {
				return true;
			}
			// if current status is logged in and retrieved status is logged in...
			if (current.isLoggedIn()) {
				// ... and the idS of the users are the same
				if (current.getProfile().getId() == result.getProfile().getId()) {
					return false;
				}
				// ... and the idS of the users are different
				else {
					return true;
				}
			}
			// if current status is logged out and the retrieved status is logged in...
			else {
				return true;
			}
		}
		else {
			// if the component has not been initialized yet and the user is not logged in
			if (current == null) {
				return false;
			}
			// if retrieved status is logged out and current is logged in
			if (current.isLoggedIn()) {
				return true;
			}
			// if retrieved status is logged out and current is logged out
			else {
				return false;
			}
		}
	}
	
	@Override
	public UserInfo updateUserInfo() {
		gws.getUserInfo(Window.Location.createUrlBuilder().setPath("/GatewayReturn.html").buildString(), new AsyncCallback<UserInfo>() {
			public void onFailure(Throwable caught) {
				broadcastMessage(MessageBroadcastType.ERROR, caught.getMessage());
			}

			public void onSuccess(UserInfo result) {
				UserInfo current = userInfo;
				userInfo = result;
				view.setUserInfo(userInfo);
				if (stateChanged(current, result)) {
					eventBus.fireEvent(new LoginStateChangedEvent(result));
				}
			}
		});
		return userInfo;
	}
	
	@Override
	public void login(AuthenticationProvider provider) {
		Window.open(userInfo.getLoginURL().get(provider), "_blank", "resizable=1,width=480,height=400");
	}

	@Override
	public void logout() {
		Window.open(userInfo.getLogoutURL(), "_blank", "width=480,height=400");
	}

	@Override
	public Widget getView() {
		return view.asWidget();
	}

	@Override
	public void onLoginStatusRequest(RequestLoginStateCheckEvent event) {
		updateUserInfo();
	}
	
	private static native void exposeCheckLogin(GatewayPresenter gp) /*-{
		$wnd.checkLogin = function() {
			$entry(gp.@nl.vu.few.ibivu.biomodels.client.presenter.GatewayPresenter::updateUserInfo()());
		};
	}-*/;

}
